package hn.sigit.logic.workflow.permits;

import hn.sigit.dao.SigitDAO;
import hn.sigit.dao.hnd.administrative.HND_BuildingPermitDAO;
import hn.sigit.dao.hnd.administrative.HND_PermitRuleGroupDAO;
import hn.sigit.dao.hnd.cadastre.HND_SpatialZoneDAO;
import hn.sigit.model.hnd.administrative.HND_BuildingPermit;
import hn.sigit.model.hnd.administrative.HND_BuildingPermitType;
import hn.sigit.model.hnd.administrative.HND_PermitRuleGroup;
import hn.sigit.model.hnd.administrative.HND_PermitType;
import hn.sigit.model.hnd.cadastre.HND_BuildingMaterial;
import hn.sigit.model.hnd.cadastre.HND_BuildingUnit;
import hn.sigit.model.hnd.cadastre.HND_LandUse;
import hn.sigit.model.hnd.cadastre.HND_Parcel;
import hn.sigit.model.hnd.cadastre.HND_SpatialZone;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.faces.model.SelectItem;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.bpm.BeginTask;
import org.jboss.seam.annotations.bpm.CreateProcess;
import org.jboss.seam.bpm.ProcessInstance;
import org.jbpm.taskmgmt.exe.TaskInstance;

@Name("buildingPermitHelper")
@Scope(value=ScopeType.CONVERSATION)
@AutoCreate
public class BuildingPermitHelper extends PermitHelper<HND_BuildingPermit> implements Serializable {
	private static final long serialVersionUID = -3421722459928810842L;
	
	private static List<SelectItem> permitTypeValueList;

	private final String BUILDING_PERMIT_PROCESS = "buildingPermitWorkflow";
	
	private HND_BuildingMaterial selectedBuildingMaterial;
	
	
	@Override
	public HND_BuildingPermit getPermit() {
		if (permit == null) {
			permit = new HND_BuildingPermit();
			permit.setRuleGroup(getPermitRuleGroup());
			
			if (getBuildingLayers().size() == 1)
				permit.getBuildingUnit().setLevel(getBuildingLayers().get(0));
		}
		return (HND_BuildingPermit) permit;
	}
	@Override
	public void setPermit(HND_BuildingPermit permit) {
		this.permit = permit;
	}
	
	public String selectParcelFromMap() {
		if (interactiveViewerHelper.getSelectedParcel() != null)
			getPermit().setSelectedZone((HND_Parcel) interactiveViewerHelper.getSelectedParcel());
		else if (interactiveViewerHelper.getHighlightedSpatialZoneList() != null
				&& interactiveViewerHelper.getHighlightedSpatialZoneList().size() > 0
				&& interactiveViewerHelper.getHighlightedSpatialZoneList().get(0) instanceof HND_Parcel)
			getPermit().setSelectedZone((HND_Parcel) interactiveViewerHelper.getHighlightedSpatialZoneList().get(0));
		
		return null;
	}
	
	public HND_BuildingMaterial getSelectedBuildingMaterial() {
		return selectedBuildingMaterial;
	}
	public void setSelectedBuildingMaterial(
			HND_BuildingMaterial selectedBuildingMaterial) {
		this.selectedBuildingMaterial = selectedBuildingMaterial;
	}
	public void addBuildingMaterial() {
		if (selectedBuildingMaterial == null) return;
		
		List<HND_BuildingMaterial> buildingMaterials = getPermit().getBuildingUnit().getBuildingMaterials();
		if (!buildingMaterials.contains(selectedBuildingMaterial))
			buildingMaterials.add(selectedBuildingMaterial);
	}
	public void deleteBuildingMaterial(HND_BuildingMaterial buildingMaterial) {
		if (buildingMaterial == null) return;
		
		List<HND_BuildingMaterial> buildingMaterials = getPermit().getBuildingUnit().getBuildingMaterials();
		buildingMaterials.remove(buildingMaterial);
	}
	
	@Override
	public void addLandUse() {
		if (selectedLandUse == null) return;
		
		List<HND_LandUse> landUses = getPermit().getBuildingUnit().getOtherLandUses();
		if (!landUses.contains(selectedLandUse))
			landUses.add(selectedLandUse);
	}
	@Override
	public void deleteLandUse(HND_LandUse landUse) {
		if (landUse == null) return;
		
		List<HND_LandUse> landUses = getPermit().getBuildingUnit().getOtherLandUses();
		landUses.remove(landUse);
	}
	
	
	public List<HND_SpatialZone> getBuildingAreaRestrictingSZList() {
		if (buildingAreaRestrictingSZList == null) {
			buildingAreaRestrictingSZList = HND_SpatialZoneDAO
					.loadSpatialZonesBySZAndLessBuiltAreaAllowed(
							getPermit().getSelectedZone(),
							getPermit().getBuildingUnit().getBuiltArea());
		}
		return buildingAreaRestrictingSZList;
	}
	public void setBuildingAreaRestrictingSZList(
			List<HND_SpatialZone> buildingAreaRestrictingSZList) {
		this.buildingAreaRestrictingSZList = buildingAreaRestrictingSZList;
	}
	
	public List<HND_SpatialZone> getNumberOfFloorsRestrictingSZList() {
		if (numberOfFloorsRestrictingSZList == null) {
			numberOfFloorsRestrictingSZList = HND_SpatialZoneDAO
					.loadSpatialZonesBySZAndLessNumberOfFloorsAllowed(
						getPermit().getSelectedZone(),
						getPermit().getBuildingUnit().getNumberOfFloors());
		}
		return numberOfFloorsRestrictingSZList;
	}
	public void setNumberOfFloorsRestrictingSZList(
			List<HND_SpatialZone> numberOfFloorsRestrictingSZList) {
		this.numberOfFloorsRestrictingSZList = numberOfFloorsRestrictingSZList;
	}
	
	public List<HND_SpatialZone> getBuildingMaterialRestrictingSZList() {
		if (buildingMaterialRestrictingSZList == null) {
			buildingMaterialRestrictingSZList = new ArrayList<HND_SpatialZone>();
			
			List<HND_SpatialZone> szCandidateList = HND_SpatialZoneDAO
					.loadSpatialZonesByInterctingSZ(
						getPermit().getSelectedZone());
			if (szCandidateList != null && szCandidateList.size() > 0)
				for (HND_SpatialZone hndSZ : szCandidateList)
					for (HND_BuildingMaterial bm : hndSZ.getPermitNorm().getForbiddenBuildingMaterials())
						//for each forbidden building material....
						if (getPermit().getBuildingUnit().getBuildingMaterials().contains(bm)) {
							if (!buildingMaterialRestrictingSZList.contains(hndSZ))
								buildingMaterialRestrictingSZList.add(hndSZ);
							if (!szBuildingMaterials(hndSZ).contains(bm))
								szBuildingMaterials(hndSZ).add(bm);
						}
		}
		return buildingMaterialRestrictingSZList;
	}
	public void setBuildingMaterialRestrictingSZList(
			List<HND_SpatialZone> buildingMaterialRestrictingSZList) {
		this.buildingMaterialRestrictingSZList = buildingMaterialRestrictingSZList;
	}
	
	@Override
	public List<HND_SpatialZone> getLandUseRestrictingSZList() {
		if (landUseRestrictingSZList == null) {
			landUseRestrictingSZList = new ArrayList<HND_SpatialZone>();

			List<HND_SpatialZone> szCandidateList = HND_SpatialZoneDAO
					.loadSpatialZonesByInterctingSZ(
						getPermit().getSelectedZone());
			if (szCandidateList != null && szCandidateList.size() > 0) {
				Set<HND_LandUse> permitLandUses = listToSet(getPermit().getBuildingUnit().getOtherLandUses());
				permitLandUses.add(getPermit().getBuildingUnit().getLandUse());
				
				for (HND_SpatialZone hndSZ : szCandidateList) {
					Set<HND_LandUse> szLandUses = listToSet(hndSZ.getOtherLandUses());
					if (hndSZ.getLandUse() != null)
						szLandUses.add(hndSZ.getLandUse());
					
					List<HND_LandUse> incompatLUs = new ArrayList<HND_LandUse>();
					if (!areLandUseSetsCompatible(permitLandUses, szLandUses, incompatLUs)) {
						landUseRestrictingSZList.add(hndSZ);
						szLandUses(hndSZ).addAll(incompatLUs);
					}
				}
			}
		}
		return landUseRestrictingSZList;
	}
	
	public List<HND_BuildingMaterial> szBuildingMaterials(HND_SpatialZone sz) {
		if (szBuildingMaterials == null) {
			szBuildingMaterials = new HashMap<HND_SpatialZone, List<HND_BuildingMaterial>>();
		}
		List<HND_BuildingMaterial> bms = szBuildingMaterials.get(sz);
		if (bms == null) {
			bms = new ArrayList<HND_BuildingMaterial>();
			szBuildingMaterials.put(sz, bms);
		}
		return bms;
	}
	public List<HND_LandUse> szLandUses(HND_SpatialZone sz) {
		if (szLandUses == null) {
			szLandUses = new HashMap<HND_SpatialZone, List<HND_LandUse>>();
		}
		List<HND_LandUse> lus = szLandUses.get(sz);
		if (lus == null) {
			lus = new ArrayList<HND_LandUse>();
			szLandUses.put(sz, lus);
		}
		return lus;
	}
	
	@Override
	public boolean isAdminAnalysisOK() {
		final List<?>[] listArr = { getBuildingAreaRestrictingSZList(), getBuildingMaterialRestrictingSZList(),
				getNumberOfFloorsRestrictingSZList(), getLandUseRestrictingSZList() };
		
		for (List<?> l : listArr)
			if (!listOK(l))
				return false;
		
		return true;
	}
	
	
	public List<TaskInstance> getTaskInstanceList() {
		return getTaskInstanceList(BUILDING_PERMIT_PROCESS);
	}

	public List<TaskInstance> getPooledTaskInstanceList() {
		return getPooledTaskInstanceList(BUILDING_PERMIT_PROCESS);
	}
	
	@End
	@CreateProcess(definition=BUILDING_PERMIT_PROCESS, processKey="#{buildingPermitHelper.permitId}")
	@Transactional
	@Override
	public String beginProcess() {
		HND_BuildingPermit hndPermit = getPermit();
		HND_BuildingUnit buildingUnit = getPermit().getBuildingUnit();
		
		beginProcessAux(hndPermit);

		SigitDAO.save(buildingUnit);
		HND_BuildingPermitDAO.save(hndPermit);
		setPermitId(hndPermit.getId());

		return "building_permit_activities";
	}

	@Override
	@BeginTask
	@Begin(join=true)
	public String startTask() {
		String taskName = org.jboss.seam.bpm.TaskInstance.instance().getTask().getName();
		setPermit(HND_BuildingPermitDAO.loadBuildingPermitByID(
				Long.parseLong(ProcessInstance.instance().getKey())));
		
		setPermitId(this.permit.getId());
		setParty(this.permit.getExtParty());
		
		return taskName;
	}

	public List<SelectItem> getPermitTypeValueList() {
		if (permitTypeValueList == null) {
			permitTypeValueList = new ArrayList<SelectItem>();
			permitTypeValueList.add(new SelectItem(null, "(seleccionar)"));
			for (HND_BuildingPermitType pt : HND_BuildingPermitType.values())
				permitTypeValueList.add(new SelectItem(pt, resBundle.loadMessage(pt.name())));
		}
		return permitTypeValueList;
	}
	
	@Override
	public List<HND_PermitRuleGroup> getPermitRuleGroupList() {
		if (permitRuleGroupList == null) {
			permitRuleGroupList = HND_PermitRuleGroupDAO.loadPermitRuleGroupsByType(HND_PermitType.BUILDING_PERMIT);
		}
		return permitRuleGroupList;
	}
	
	@Override
	public HND_PermitRuleGroup getPermitRuleGroup() {
		if (permitRuleGroup == null) {
			permitRuleGroup = generalHelper.getSystemConfiguration().getBuildingPermitRuleGroup();
		}
		return permitRuleGroup;
	}
	
	
	@Override
	public HND_LandUse getLandUse() {
		return getPermit().getBuildingUnit().getLandUse();
	}
	@Override
	public List<HND_LandUse> getOtherLandUses() {
		return getPermit().getBuildingUnit().getOtherLandUses();
	}
	
}

